package org.dromara.business.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.baomidou.mybatisplus.core.metadata.IPage;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.business.domain.Goods;
import org.dromara.business.domain.User;
import org.dromara.business.service.BusinessConfigService;
import org.dromara.business.service.GoodsService;
import org.dromara.business.service.UserFlowingService;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.DateUtils;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * vip
 *
 * @author zlj
 * @date 2024-08-01
 */
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/business/vip")
public class VipController extends BaseController {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    private final String USER_SIGN_KEY = "sign:";
    private final BusinessConfigService configService;
    private final UserFlowingService userFlowingService;
    private final ISysUserService userService;
    private final GoodsService goodsService;
    private final BusinessConfigService businessConfigService;

    /**
     * 签到接口
     */
    @GetMapping("/sign")
    @RepeatSubmit()
    public R<Void> sign() {
        //生成key
        String key = this.getKey();
        //获取本月第几天
        int dayOfMonth = DateUtil.dayOfMonth(DateUtils.getNowDate());
        //判断今日是否签到
        //查询redis
        List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
            BitFieldSubCommands.create()
                .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        if ((result.get(0) & 1) == 1) {
            throw new ServiceException("今日已签到");
        }
        //存到redis
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth - 1, true);
        //增加积分
        String points = configService.queryValueByKey("points");
        // userFlowingService.addAmount(LoginHelper.getUserId(), Integer.valueOf(points), BusinessConstants.FLOWING_TYPE_SIGN, null);
        return R.ok();
    }

    /**
     * 判断今天是否打卡
     */
    @GetMapping("/getTodayIsSign")
    public R<Boolean> getTodayIsSign() {
        //生成key
        String key = this.getKey();
        //获取本月第几天
        int dayOfMonth = DateUtil.dayOfMonth(DateUtils.getNowDate());
        //查询redis
        List<Long> result = stringRedisTemplate.opsForValue().bitField(key,
            BitFieldSubCommands.create()
                .get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
        return R.ok((result.get(0) & 1) == 1);
    }

    /**
     * 老用户绑定邀请人
     */
    @GetMapping("/bindSuperior")
    @Transactional(rollbackFor = Exception.class)
    public R<String> bindSuperior(Long userId) {
        log.warn("老用户绑定邀请人:{}",userId);
        try {
            Long currentUserId = LoginHelper.getUserId();
            SysUser currentUser = userService.getById(currentUserId);

            // 检查当前用户是否已有上级
            if (currentUser.getSuperiorId() != null) {
                return R.ok("当前用户已有上级，无需绑定。");
            }

            // 检查要绑定的用户是否是当前用户的下级
            if (userService.isDown(userId)) {
                return R.ok("不能绑定自己的下级。");
            }

            // 绑定上级
            currentUser.setSuperiorId(userId);
            userService.updateById(currentUser);

            // 获取每日分享次数配置
            String configValue = businessConfigService.queryValueByKey("number_shares_per_day");
            String sharePoints = businessConfigService.queryValueByKey("share_points");
            Integer numberSharesPerDay = Integer.valueOf(configValue);
            Integer points = Integer.valueOf(sharePoints);

            // 更新上级的积分和分享次数
            SysUser superior = userService.getById(userId);
            if (superior != null) {
                if (superior.getExchange() != null && superior.getExchange() >= numberSharesPerDay) {
                    return R.ok("今天分享次数已用完！");
                }

                if (superior.getSuperiorId() == null) {
                    superior.setPoints(0);
                }
                if (superior.getExchange() == null) {
                    superior.setExchange(0);
                }

                superior.setExchange(superior.getExchange() + 1);
                superior.setPoints(superior.getPoints() + points);
                userService.updateById(superior);
            }

            return R.ok("上级绑定成功。");
        } catch (NumberFormatException e) {
            log.error("配置项 'number_shares_per_day' 解析错误", e);
            return R.fail("配置项解析错误，请联系管理员。");
        } catch (Exception e) {
            log.error("老用户绑定邀请人失败", e);
            return R.fail("老用户绑定邀请人失败！");
        }
    }



    private String getKey() {
        Long userId = LoginHelper.getUserId();
        Date nowDate = DateUtils.getNowDate();
        String keySuffix = DateUtil.format(nowDate, ":yyyyMM");
        return USER_SIGN_KEY + userId + keySuffix;
    }

    /**
     * 修改用户头像昵称信息
     *
     * @return 用户信息
     */
    @PostMapping("/updateWxInfo")
    @Transactional(rollbackFor = Exception.class)
    public R<Void> updateWxInfo(String nickName, String avatar) {
        Long userId = LoginHelper.getUserId();
        userService.lambdaUpdate()
            .set(StrUtil.isNotBlank(nickName), SysUser::getNickName, nickName)
            .set(StrUtil.isNotBlank(avatar), SysUser::getWxAvatar, avatar)
            .eq(SysUser::getUserId, userId)
            .update();
        goodsService.lambdaUpdate().set(Goods::getUserProfile, avatar).eq(Goods::getCreateBy, userId).update();
        return R.ok();
    }

    /**
     * 获取定位
     * @param location
     * @return
     */
    @RepeatSubmit(interval = 1000, message = "正在获取定位,请稍后")
    @GetMapping("/getAddress")
    public R<Map<String, String>> getAddress(@RequestParam String location) {
        String key = configService.queryValueByKey("map");
        Map<String, Object> param = new HashMap<>();
        param.put("key", key);
        param.put("location", location);
        String response = HttpUtil.get("https://apis.map.qq.com/ws/geocoder/v1/", param);
        JSONObject result = JSONUtil.parseObj(response);
        Integer status = result.getInt("status");
        if (status != 0) {
            log.error("解析地址错误: 错误码: " + status + ", 错误信息: " + result.getStr("message"));
            throw new ServiceException("解析地址错误, 请联系管理员");
        }

        JSONObject result1 = result.getJSONObject("result");
        JSONObject addressComponent = result1.getJSONObject("ad_info");

        // 提取省、市、区字段
        String adcode = addressComponent.getStr("adcode");
        String province = addressComponent.getStr("province");
        String city = addressComponent.getStr("city");
        String district = addressComponent.getStr("district");

        //修改用户当前位置
        Long userId = LoginHelper.getUserId();
        SysUser user = userService.getById(userId);
        user.setCity(city);
        userService.updateById(user);
        // 将提取的字段放入一个Map中返回
        Map<String, String> addressInfo = new HashMap<>();
        addressInfo.put("province", province);
        addressInfo.put("city", city);
        addressInfo.put("district", district);
        addressInfo.put("adcode", adcode);

        return R.ok(addressInfo);
    }


    /**
     * 获取省市区
     * @return
     */
    @RepeatSubmit(interval = 1000, message = "正在获取定位,请稍后")
    @GetMapping("/getAddressCity")
    public R<Map<String, String>> getAddressCity() {
        String key = configService.queryValueByKey("map");

        String response = HttpUtil.get("https://apis.map.qq.com/ws/district/v1/list?key="+ key);
        JSONObject result = JSONUtil.parseObj(response);
        System.out.println(result);
        Integer status = result.getInt("status");
        if (status != 0) {
            log.error("解析地址错误: 错误码: " + status + ", 错误信息: " + result.getStr("message"));
            throw new ServiceException("解析地址错误, 请联系管理员");
        }
        JSONObject result1 = result.getJSONObject("result");

        ObjectMapper objectMapper = new ObjectMapper();


        Location location = new Location();



        // 将提取的字段放入一个Map中返回
        Map<String, String> addressInfo = new HashMap<>();


        return R.ok(addressInfo);
    }



    /**
     * 查询团队
     */
    @GetMapping("/getMyTeam")
    public R<Map<String, Object>> getMyTeam(PageQuery query) {
        Map<String, Object> map = new HashMap<>();
        //查询团队业绩
//        SysUser user = userService.getById(LoginHelper.getUserId());
//        map.put("teamAmount", "");
        //查询团队
        IPage<SysUser> page = userService.lambdaQuery().eq(SysUser::getSuperiorId, LoginHelper.getUserId()).page(query.build());
        if (CollectionUtil.isEmpty(page.getRecords())) {
            map.put("team", page);
        }
        List<SysUserVo> sysUserVos = BeanUtil.copyToList(page.getRecords(), SysUserVo.class);
        IPage<SysUserVo> result = query.build();
        result.setTotal(page.getTotal());
        result.setRecords(sysUserVos);
        map.put("team", result);
        return R.ok(map);
    }

    @GetMapping("/getTeam")
    public R<Map<String, Object>> getMyTeam(PageQuery query, Long userId) {
        Map<String, Object> map = new HashMap<>();
        //查询团队
        IPage<SysUser> page = userService.lambdaQuery().eq(SysUser::getSuperiorId, userId).page(query.build());
        if (CollectionUtil.isEmpty(page.getRecords())) {
            map.put("team", page);
        }
        List<SysUserVo> sysUserVos = BeanUtil.copyToList(page.getRecords(), SysUserVo.class);
        IPage<SysUserVo> result = query.build();
        result.setTotal(page.getTotal());
        result.setRecords(sysUserVos);
        map.put("team", result);
        return R.ok(map);
    }





    class Location {
        private double lat;
        private double lng;

        // Getters and Setters
        public double getLat() {
            return lat;
        }

        public void setLat(double lat) {
            this.lat = lat;
        }

        public double getLng() {
            return lng;
        }

        public void setLng(double lng) {
            this.lng = lng;
        }
    }

    class City {
        private String id;
        private String name;
        private String fullname;
        private List<String> pinyin;
        private Location location;
        private List<Integer> cidx;

        // Getters and Setters
        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getFullname() {
            return fullname;
        }

        public void setFullname(String fullname) {
            this.fullname = fullname;
        }

        public List<String> getPinyin() {
            return pinyin;
        }

        public void setPinyin(List<String> pinyin) {
            this.pinyin = pinyin;
        }

        public Location getLocation() {
            return location;
        }

        public void setLocation(Location location) {
            this.location = location;
        }

        public List<Integer> getCidx() {
            return cidx;
        }

        public void setCidx(List<Integer> cidx) {
            this.cidx = cidx;
        }
    }

}
